from fastapi import APIRouter, HTTPException, Query, File, UploadFile
from typing import List, Optional
from backend.api.alarm_service import AlarmService
from backend.models.alarm import Alarm, AlarmCreate, AlarmQuery, AnalysisResult
import pandas as pd
from datetime import datetime
import os
import tempfile

router = APIRouter(prefix="/api/v1/alarms", tags=["alarms"])

# 创建告警服务实例
alarm_service = AlarmService()

        
@router.get("/", response_model=List[Alarm])    ###完整URL: http://localhost:8000/api/v1/alarms?skip=0&limit=10
async def get_alarms_list(skip: int = 0, limit: int = 100):
    """获取告警列表"""
    try:
        alarms = alarm_service.get_alarms_list(skip, limit)
        return alarms
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.post("/", response_model=dict)
async def create_alarm(alarm: AlarmCreate):
    """创建告警"""
    try:
        success = alarm_service.create_alarm(alarm)
        if success:
            return {"message": "告警创建成功"}
        else:
            raise HTTPException(status_code=500, detail="告警创建失败")
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/{global_alarm_id}", response_model=Alarm)
async def get_alarm_detail(global_alarm_id: str):
    """获取告警详情"""
    try:
        alarm = alarm_service.get_alarm_detail(global_alarm_id)
        if alarm:
            return alarm
        else:
            raise HTTPException(status_code=404, detail="告警未找到")
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/query/count", response_model=int)
async def get_alarms_count_endpoint(
    global_alarm_id: Optional[str] = None,
    alarm_status: Optional[str] = None,
    alarm_title: Optional[str] = None,
    alarm_type: Optional[str] = None,
    alarm_level: Optional[str] = None,
    region: Optional[str] = None,
    datacenter: Optional[str] = None,
    device_name: Optional[str] = None,
    device_type: Optional[str] = None,
    device_vendor: Optional[str] = None,
    dispatch_status: Optional[str] = None,
    resource_pool: Optional[str] = None,
    start_time: Optional[str] = None,
    end_time: Optional[str] = None
):
    """根据条件获取告警总数"""
    try:
        query = AlarmQuery(
            global_alarm_id=global_alarm_id,
            alarm_status=alarm_status,
            alarm_title=alarm_title,
            alarm_type=alarm_type,
            alarm_level=alarm_level,
            region=region,
            datacenter=datacenter,
            device_name=device_name,
            device_type=device_type,
            device_vendor=device_vendor,
            dispatch_status=dispatch_status,
            resource_pool=resource_pool,
            start_time=start_time,
            end_time=end_time
        )
        count = alarm_service.get_alarms_count_by_query(query)
        return count
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.post("/import/excel", response_model=dict)
async def import_excel_file(file: UploadFile = File(...)):
    """从Excel文件导入告警数据"""
    try:
        # 验证文件格式
        if not file.filename.endswith(('.xlsx', '.xls')):
            raise HTTPException(status_code=400, detail="只支持Excel文件(.xlsx, .xls)")
        
        # 保存临时文件
        with tempfile.NamedTemporaryFile(delete=False, suffix='.xlsx') as temp_file:
            content = await file.read()
            temp_file.write(content if isinstance(content, bytes) else content.encode())
            temp_path = temp_file.name
        
        try:
            # 读取Excel文件
            df = pd.read_excel(temp_path)
            
            # Excel字段映射到数据库字段
            field_mapping = {
                '告警全局标识': 'global_alarm_id',
                '告警状态': 'alarm_status',
                '告警标题': 'alarm_title',
                '告警类型': 'alarm_type',
                '标准告警级别': 'alarm_level',
                '告警发生时间': 'occurrence_time',
                '告警清除时间': 'clear_time',
                '大区': 'region',
                '机房': 'datacenter',
                '设备名称': 'device_name',
                '设备类型': 'device_type',
                '设备厂商（虚层）': 'device_vendor',
                '派单状态': 'dispatch_status',
                '资源池': 'resource_pool',
                '告警正文': 'alarm_content'
            }
            
            # 验证必要字段是否存在
            required_fields = ['告警全局标识', '告警标题', '告警类型', '标准告警级别', 
                             '告警发生时间', '大区', '机房', '设备名称', '设备类型']
            missing_fields = [f for f in required_fields if f not in df.columns]
            if missing_fields:
                raise HTTPException(
                    status_code=400, 
                    detail=f"Excel文件缺少必要字段: {', '.join(missing_fields)}"
                )
            
            # 转换数据为AlarmCreate对象列表
            alarms = []
            parse_error_count = 0
            
            print(f"\n开始解析Excel数据，共 {len(df)} 行...")
            
            for row_num, (_, row) in enumerate(df.iterrows(), 1):
                try:
                    alarm_data = {}
                    for excel_field, db_field in field_mapping.items():
                        if excel_field in df.columns:
                            value = row[excel_field]
                            # 处理时间字段
                            if db_field in ['occurrence_time', 'clear_time']:
                                if value is not None and not (isinstance(value, float) and pd.isna(value)):
                                    if isinstance(value, str):
                                        try:
                                            alarm_data[db_field] = datetime.strptime(value, '%Y-%m-%d %H:%M:%S')
                                        except:
                                            try:
                                                alarm_data[db_field] = datetime.strptime(value, '%Y/%m/%d %H:%M:%S')
                                            except:
                                                alarm_data[db_field] = datetime.fromisoformat(str(value))
                                    else:
                                        alarm_data[db_field] = value
                                else:
                                    if db_field == 'clear_time':
                                        alarm_data[db_field] = None
                            else:
                                # 处理其他字段，将NaN转换为默认值
                                if value is not None and not (isinstance(value, float) and pd.isna(value)):
                                    alarm_data[db_field] = str(value)
                                else:
                                    # 为必填字段提供默认值
                                    if db_field in ['global_alarm_id', 'alarm_status', 'alarm_title', 
                                                   'alarm_type', 'alarm_level', 'region', 'datacenter',
                                                   'device_name', 'device_type', 'device_vendor',
                                                   'dispatch_status', 'resource_pool', 'alarm_content']:
                                        alarm_data[db_field] = ''
                    
                    # 创建AlarmCreate对象
                    alarm = AlarmCreate(**alarm_data)
                    alarms.append(alarm)
                    
                    # 每100条打印一次进度
                    if row_num % 100 == 0:
                        print(f"已解析 {row_num}/{len(df)} 行")
                        
                except Exception as e:
                    parse_error_count += 1
                    print(f"⚠️ 解析第{row_num}行数据失败: {str(e)}")
                    if parse_error_count <= 3:  # 只打印前3个错误的详细信息
                        print(f"   数据内容: {row.to_dict()}")
                    continue
            
            print(f"\n解析完成! 成功解析: {len(alarms)}, 解析失败: {parse_error_count}\n")
            
            # 批量导入到数据库
            success_count = 0
            fail_count = 0
            duplicate_count = 0
            
            print(f"\n开始导入 {len(alarms)} 条告警数据...")
            
            for i, alarm in enumerate(alarms, 1):
                try:
                    if alarm_service.create_alarm(alarm):
                        success_count += 1
                        if i % 10 == 0:  # 每10条打印一次进度
                            print(f"进度: {i}/{len(alarms)} - 成功: {success_count}, 失败: {fail_count}, 重复: {duplicate_count}")
                    else:
                        fail_count += 1
                except Exception as e:
                    error_msg = str(e)
                    if "UNIQUE constraint failed" in error_msg or "告警已存在" in error_msg:
                        duplicate_count += 1
                        print(f"重复数据跳过: {alarm.global_alarm_id}")
                    else:
                        fail_count += 1
                        print(f"创建告警失败 [{alarm.global_alarm_id}]: {error_msg}")
            
            print(f"\n导入完成! 总计: {len(alarms)}, 成功: {success_count}, 失败: {fail_count}, 重复: {duplicate_count}\n")
            
            return {
                "success": True,
                "message": f"成功导入 {success_count} 条告警数据，重复 {duplicate_count} 条，失败 {fail_count} 条",
                "total_rows": len(df),
                "success_count": success_count,
                "fail_count": fail_count,
                "duplicate_count": duplicate_count
            }
            
        finally:
            # 删除临时文件
            if os.path.exists(temp_path):
                os.remove(temp_path)
    
    except HTTPException:
        raise
    except Exception as e:
        print(f"导入Excel文件失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"导入失败: {str(e)}")

# ==================== 文件监听 API ====================

@router.post("/monitor/start", response_model=dict)
async def start_file_monitoring(watch_path: Optional[str] = None):
    """启动文件监听服务"""
    try:
        result = alarm_service.start_file_monitoring(watch_path)
        return result
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.post("/monitor/stop", response_model=dict)
async def stop_file_monitoring():
    """停止文件监听服务"""
    try:
        result = alarm_service.stop_file_monitoring()
        return result
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/monitor/status", response_model=dict)
async def get_monitoring_status():
    """获取文件监听状态"""
    try:
        result = alarm_service.get_monitoring_status()
        return result
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/monitor/latest-file", response_model=dict)
async def get_latest_file():
    """获取最新发现的告警导出Excel文件"""
    try:
        result = alarm_service.get_latest_file()
        return result
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

# ==================== 邮件发送 API ====================

@router.post("/email/send", response_model=dict)
async def send_analysis_email(
    analysis_dir: Optional[str] = None,
    sender_email: Optional[str] = None,
    sender_password: Optional[str] = None
):
    """发送分析报告邮件"""
    try:
        kwargs = {}
        if analysis_dir:
            kwargs['analysis_dir'] = analysis_dir
        if sender_email:
            kwargs['sender_email'] = sender_email
        if sender_password:
            kwargs['sender_password'] = sender_password
        
        result = alarm_service.send_analysis_email(**kwargs)
        return result
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

# ==================== 本地大模型分析 API ====================

@router.post("/llm/analyze", response_model=dict)
async def call_llm_analyze(file: UploadFile = File(None)):
    """调用本地大模型分析告警数据并生成Markdown文档"""
    try:
        # 如果提供了文件，则保存并使用该文件进行分析
        if file and file.filename:
            # 验证文件格式
            if not file.filename.endswith(('.xlsx', '.xls')):
                raise HTTPException(status_code=400, detail="只支持Excel文件(.xlsx, .xls)")
            
            # 保存临时文件
            with tempfile.NamedTemporaryFile(delete=False, suffix='.xlsx') as temp_file:
                content = await file.read()
                temp_file.write(content if isinstance(content, bytes) else content.encode())
                temp_path = temp_file.name
            
            try:
                # 使用上传的文件进行分析
                result = alarm_service.analyze_alarms_with_llm(file_path=temp_path)
                
                # 如果分析成功，将结果文件复制到与临时文件相同的目录下的analysis_results文件夹中
                if result.get("success") and result.get("output_dir"):
                    # 获取临时文件所在目录
                    temp_dir = os.path.dirname(temp_path)
                    # 创建目标analysis_results目录
                    target_analysis_dir = os.path.join(temp_dir, 'analysis_results')
                    
                    # 如果源目录存在且目标目录不存在，则复制整个目录
                    if os.path.exists(result["output_dir"]) and not os.path.exists(target_analysis_dir):
                        import shutil
                        shutil.copytree(result["output_dir"], target_analysis_dir)
                        # 更新返回结果中的路径
                        result["output_dir"] = target_analysis_dir
                        result["markdown_path"] = os.path.join(target_analysis_dir, 'analysis_report.md')
                        result["message"] = f"分析报告生成成功，文件保存在: {result['markdown_path']}"
                
                return result
            finally:
                # 清理临时文件
                if os.path.exists(temp_path):
                    os.unlink(temp_path)
        else:
            # 如果没有提供文件，使用默认逻辑（查找最新文件）
            result = alarm_service.analyze_alarms_with_llm()
            return result
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

# ==================== 柱状图数据分析 API ====================

@router.get("/analysis/charts", response_model=dict)
async def get_chart_analysis():
    """获取柱状图数据分析（四大场景）"""
    try:
        result = alarm_service.get_chart_analysis()
        return result
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))